畫畫
http://www.effectgames.com/demos/canvascycle/
https://www.w3schools.com/graphics/canvas_coordinates.asp
https://www.w3schools.com/graphics/game_sound.asp
刷上藍色漸層背景增添質感
以下這段程式,若非不是一開始就畫出,就必須設定
globalCompositeOperation,否則,預設會蓋掉先前的內容
https://www.w3schools.com/tags/playcanvas.asp?filename=playcanvas_globalcompop&preval=source-over
ctx.globalCompositeOperation = "destination-over";
var grd = ctx.createLinearGradient(0, 0, 0, 50);
grd.addColorStop(0, "white");
grd.addColorStop(1, "#0000EE");
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 200, 50);
畫線
var canvas = document.getElementById("myCanvas2");
var ctx = canvas.getContext("2d");
ctx.moveTo(0, 0);
ctx.lineTo(100, 50);
ctx.moveTo(100, 50);
ctx.lineTo(200, 0);
ctx.stroke(); //定案
塗滿
var canvas = document.getElementById("myCanvas3");
var ctx = canvas.getContext("2d");
ctx.moveTo(0, 0);
ctx.lineTo(100, 50);
ctx.lineTo(200, 0);
ctx.fill();
劃十字
// width="400px" height="300px"
ctx.moveTo(0, 150);
ctx.lineTo(400, 150);
ctx.stroke();
ctx.moveTo(200, 0);
ctx.lineTo(200, 300);
ctx.stroke();
用來對齊文字(自己的口絕:起始點在中間 => 相反)
ctx.font = "64px Arial";
ctx.textBaseline = "top"; //top ,middle ,botton
ctx.textAlign = "left"; //對齊起點 ; left, center, right
ctx.fillText("hello", 200, 150);
還原 讓後面的設計不受此處影響
let bakFillStyle = ctx.fillStyle;
ctx.font = "8px Arial italic";
ctx.textBaseline = "top";
ctx.textAlign = "center";
ctx.fillStyle = "#FFFFFF";
ctx.fillText("Powered by HTML5", 100, 35);
ctx.fillStyle = bakFillStyle; //
arc畫圓圈圈
arc(120, 100, 80, 0, 2 * Math.PI [0~2PI] ,true[是否逆時針:預設False])
ctx.arc(120, 100, 80, 0, 2 * Math.PI, true);
ctx.stroke(); //1.輸出
// ctx.fill(); //2.填滿
ctx.clip(); //3.裁切畫布
ctx.drawImage(imgRabbit, 0, 0); //3.放圖片
做一個重複的
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage
var ctxSmall = canvasSmall.getContext("2d");
// (canvasLab, 來源[0, 0, 240, 200], 目的[0, 0, 120, 100])
ctxSmall.drawImage(canvasLab, 0, 0, 240, 200, 0, 0, 120, 100);
圖片灰階
原理:紅綠藍相同,為灰色(數字大小只差在深淺)
把紅綠藍抓出來,取得平均數,作為灰階的漸層
var imgData = ctxSmall.getImageData(0, 0, 120, 100);
console.log(imgData);
var data = imgData.data;
//data.length 48000 ; 一個畫素4位元 ; 0, 4, ,8 ,12
for (var i = 0; i < data.length; i += 4) {
var avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
data[i] = avg; // red ; 4
data[i + 1] = avg; // green ; 5
data[i + 2] = avg; // blue ; 6
}
ctxSmall.putImageData(imgData, 0, 0);
畫布轉圖片 toDataURL
如同 img src="data:image/png;base64,iVBORw0KGgoAAAANSUhE............."
imgView.src = canvasSmall.toDataURL("image/png");
撞球
var canvas = document.getElementById("surface");
var ctx = canvas.getContext("2d");
setInterval(function () {
//撞到牆壁反彈
//下
if (ball.y + ball.r >= surface.height) {
ball.vy = Math.abs(ball.vy) * -1;
}
//上
if (ball.y + ball.r <= 0) {
ball.vy = Math.abs(ball.vy);
}
//右
if (ball.x + ball.r >= surface.width) {
ball.vx = Math.abs(ball.vx) * -1;
}
//左
if (ball.x + ball.r <= 0) {
ball.vx = Math.abs(ball.vx);
}
//擦掉
ctx.fillStyle = "white";
ctx.fillRect(0, 0, surface.width, surface.height);
//球移動 20 22 24 26 28...
ball.x += ball.vx;
ball.y += ball.vy;
//不會重複畫 (重新計算路徑)
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2); //畫球
ctx.stroke();
}, 1000 / 70);
下堂課接續
(2)啟用keyboard事件
var key_flag = "none";
document.onkeydown = function (e) {
console.log(e);
console.log(e.keyCode); //37左 38上 39右 40下
switch (e.keyCode) {
case 37:
// 按左 提早轉向(*-1)
// abs回傳一個數字的絕對值
// ball.vx = Math.abs(ball.vx) * -1;
// 雖然可以執行但是難維護
//維護用
key_flag = "left";
break;
case 38:
key_flag = "up";
break;
case 39:
key_flag = "right";
break;
case 40:
key_flag = "down";
break;
}
};
(3)撞到方向(上),按下按鈕要反彈(相反:下)
if (ball.y + ball.r >= surface.height || key_flag == "up") {
ball.vy = Math.abs(ball.vy) * -1;
}
// 上
if (ball.y + ball.r <= 0 || key_flag == "down") {
ball.vy = Math.abs(ball.vy);
}
// 右
// if (ball.x + ball.r >= surface.width) {
// ball.vx = Math.abs(ball.vx) * -1;
// }
if (ball.x + ball.r >= surface.width || key_flag == "left") {
ball.vx = Math.abs(ball.vx) * -1;
}
// 左
if (ball.x + ball.r <= 0 || key_flag == "right") {
ball.vx = Math.abs(ball.vx);
}
(4)按完恢復原狀
key_flag = "none";
4.canvas 對 focus 無效 所以 無反應
鍵盤按下時 事件
canvas 對 focus 無效 所以 無反應
<canvas id="surface" height="400" width="600" style="border: 1px solid gray">
</canvas>
surface.onkeydown = function (e) {
console.log(e);
};
修改為document
document.onkeydown = function (e) {
console.log(e);
};
5.不要用setinterval偵測是否按下按鍵,請使用事件onkeydown
不管設定多少時間偵測一次,都會有遺漏
setInterval(function () {
}, 1000); 1s
document.onkeydown = function (e) {
console.log(e);
console.log(e.keyCode); //37左 38上 39右 40下
switch (e.keyCode) {
case 37:
key_flag = "left";
break;
case 38:
key_flag = "up";
break;
case 39:
key_flag = "right";
break;
case 40:
key_flag = "down";
break;
}
};
6.關於圓周率、sin、cos...三角函數 詳見JS_API影片03(死亡)
7.ChartJS - 直線圖 (Lab_ChartJS_01 > lab.html)
https://www.chartjs.org/
(1)安裝 / 引用 Chart.js
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0/dist/Chart.min.js"></script>
(2)建立畫布、畫筆
<canvas id="chartCanvas"></canvas>
var cityPopulationList = [3800, 2570, 2374, 2106, 1859];
var cityPopulationList2030 = [3719, 3606, 3075, 2344, 1988];
var cityNameList = ["Tokyo", "Delhi", "Shanghai", "Sao Paulo", "New York"];
(3)畫畫
https://www.chartjs.org/docs/latest/api/interfaces/ChartTypeRegistry.html
var populationChart = new Chart(ctx, {
type: "bar", //"bar"物件
data: {
labels: cityNameList, // X 軸項目清單
//datasets 陣列
datasets: [
{
label: "population",
data: cityPopulationList, //陣列
// 著色:
backgroundColor: "rgba(14,72,100,0.2)",
borderColor: "rgba(14,72,100,1.0)",
borderWidth: 1,
},
{
label: "population",
data: cityPopulationList, //陣列
// 著色:
backgroundColor: "rgba(14,72,100,0.5)",
borderColor: "rgba(14,72,100,0.5)",
borderWidth: 10,
},
],
},
});
7.ChartJS - 直線圖 (Lab_ChartJS_02 > lab.html)
type: "line"
8.ChartJS - pie圓餅 + doughnut甜甜圈 (Lab_ChartJS_03 > lab.html)
type: "doughnut"
var pieChart = new Chart(ctx, {
type: "doughnut", //"pie"
data: {
labels: cityNameList,
datasets: [
{
data: cityPopulationList,
backgroundColor: ["#3e95cd", "#8e5ea2", "#3cba9f", "#e8c3b9", "#c45850"],
},
//第二圈
{
data: cityPopulationList2030,
backgroundColor: ["#3e95cd", "#8e5ea2", "#3cba9f", "#e8c3b9", "#c45850"],
},
],
},
options: {
title: {
display: true,
text: "Population",
},
cutoutPercentage: 30, //粗細
},
});
9.ChartJS - scatter散佈圖 + bubble氣泡圖 (Lab_ChartJS_04 > lab.html)
var dataList = [];
for (let i = 1; i <= 10; i++) {
let dataItem = {
x: Math.floor(Math.random() * 100),
y: Math.floor(Math.random() * 100),
r: Math.floor(Math.random() * 20), //半徑
};
dataList.push(dataItem);
}
// console.log(JSON.stringify(dataList));
var ctx = document.getElementById("chartCanvas");
var labChart = new Chart(ctx, {
type: "bubble", // bubble使用到r ; scatter
data: {
datasets: [
{
label: "random X-Y",
data: dataList,
backgroundColor: "rgba(14,72,100,0.2)",
borderColor: "rgba(14,72,100,1.0)",
borderWidth: 1,
},
],
},
});
10.three.js (Lab_Three.js > lab.html)
https://threejs.org/
(1)引用
<script src="js/three.min.js"></script>
(2)製作畫布
<div id="cinema"></div>
(3)畫布 加入 canvas 元素
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById("cinema").appendChild(renderer.domElement);
(4)建立 Scene (場景)
var scene = new THREE.Scene();
scene.background = new THREE.Color(0x000000);
(5)建立 Camera (照相機)
相機參數
https://www.script-tutorials.com/webgl-with-three-js-lesson-9/
const camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 0.1, 10000);
camera.position.set(0, 0, 500);
scene.add(camera);
(6)拍照
https://www.script-tutorials.com/webgl-with-three-js-lesson-9/
const camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 0.1, 10000);
camera.position.set(0, 0, 500); //距離遠近
scene.add(camera);
var sphere = new THREE.SphereGeometry(200, 50, 50);
var material = new THREE.MeshNormalMaterial();
var mesh = new THREE.Mesh(sphere, material);
mesh.position.z = -300;
scene.add(mesh);
(7)照片放到畫布上
Render(輸出/算圖/描繪/渲染) 影像,呼叫 Renderer 描繪出作品:
renderer.render(scene, camera);
(8)包地球外皮,材質下載
var loader = new THREE.TextureLoader();
loader.load("images/earth.jpg", function (texture) {
mesh.material = new THREE.MeshBasicMaterial({ map: texture, overdraw: 0.5 });
renderer.render(scene, camera);
});
(9)轉動
自己轉轉 似setInterval/setTimeout每秒動
requestAnimationFrame(doRender);
function doRender() {
try {
mesh.rotation.y += 0.01;
} catch (e) {}
renderer.render(scene, camera);
requestAnimationFrame(doRender);
}
鍵盤轉轉
document.onkeydown = function (e) {
switch (event.keyCode) {
case 38: // up
mesh.rotation.x -= 0.2;
break;
case 40: // down
mesh.rotation.x += 0.2;
break;
case 37: // left
mesh.rotation.y -= 0.2;
break;
case 39: // right
mesh.rotation.y += 0.2;
break;
}
event.preventDefault();
};
滑鼠轉轉
var lastMove = {
x: window.innerWidth / 2,
y: window.innerHeight / 2,
};
var isMouseDown = false;
document.onmousedown = function () {
isMouseDown = true;
lastMove.x = event.clientX;
lastMove.y = event.clientY;
};
document.onmouseup = function () {
isMouseDown = false;
};
document.onmousemove = function () {
if (isMouseDown == false) {
return;
}
var moveX = event.clientX - lastMove.x;
var moveY = event.clientY - lastMove.y;
mesh.rotation.y += moveX * 0.0002;
mesh.rotation.x += moveY * 0.0002;
lastMove.x = e.clientX;
lastMove.y = e.clientY;
};
11.WebCam - 拍照 (WebCam > lab.html)
(1)引用webcam
<script src="webcam.min.js"></script>
(2)WebCam 啟動程式
Webcam.set({
width: 320,
height: 240,
image_format: 'jpeg',
jpeg_quality: 90
});
Webcam.attach('#cameraDiv');
(3)照片怎麼存
//製作畫布
var viewContext = viewPort.getContext('2d')
Webcam.snap(function (snappedImage) {
// console.log(snappedImage);
let bufferImage = new Image();
bufferImage.src = snappedImage;
bufferImage.onload = function () {
viewContext.drawImage(bufferImage, 0, 0, 320, 240);
}
}); // End of Webcam.snap